package com.hsu.hsurpc.serializer;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hsu.hsurpc.model.RpcRequest;
import com.hsu.hsurpc.model.RpcResponse;

import java.io.IOException;

/**
 * JSON 序列化器实现，使用 Jackson 进行对象的序列化和反序列化
 * @Author Hsu琛君珩
 * @Date 2024-09-19 17:03
 * @Description
 * @Version: v1.0.0
 */
public class JsonSerializer implements Serializer {

    // 创建一个静态的 ObjectMapper 实例，用于处理 JSON 序列化和反序列化
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     * 将对象序列化为字节数组
     *
     * @param obj 需要序列化的对象
     * @return 序列化后的字节数组
     * @throws IOException 如果序列化失败
     */
    @Override
    public <T> byte[] serialize(T obj) throws IOException {
        return OBJECT_MAPPER.writeValueAsBytes(obj);
    }

    /**
     * 将字节数组反序列化为对象
     *
     * @param bytes 字节数组
     * @param classType 需要反序列化成的对象类型
     * @return 反序列化后的对象
     * @throws IOException 如果反序列化失败
     */
    @Override
    public <T> T deserialize(byte[] bytes, Class<T> classType) throws IOException {
        T obj = OBJECT_MAPPER.readValue(bytes, classType);

        // 如果反序列化的对象是 RpcRequest 或 RpcResponse，进一步处理参数类型转换
        if (obj instanceof RpcRequest) {
            return hanldeRequest((RpcRequest) obj, classType);
        }
        if (obj instanceof RpcResponse) {
            return handleResponse((RpcResponse) obj, classType);
        }

        return obj;
    }

    /**
     * 处理 RpcRequest 中的参数类型，防止泛型擦除问题导致反序列化错误
     *
     * @param rpcRequest 反序列化后的 Rpc 请求对象
     * @param type 类型信息
     * @return 处理后的 RpcRequest
     * @throws IOException 如果参数类型转换失败
     */
    private <T> T hanldeRequest(RpcRequest rpcRequest, Class<T> type) throws IOException {
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();
        Object[] args = rpcRequest.getArgs();

        // 遍历所有参数，根据参数类型重新进行序列化和反序列化
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> clazz = parameterTypes[i];
            if (!clazz.isAssignableFrom(args[i].getClass())) {
                // 将参数序列化为字节再反序列化为正确的类型
                byte[] argBytes = OBJECT_MAPPER.writeValueAsBytes(args[i]);
                args[i] = OBJECT_MAPPER.readValue(argBytes, clazz);
            }
        }
        return type.cast(rpcRequest);
    }

    /**
     * 处理 RpcResponse 中的数据类型，防止泛型擦除问题导致反序列化错误
     *
     * @param rpcResponse 反序列化后的 Rpc 响应对象
     * @param type 类型信息
     * @return 处理后的 RpcResponse
     * @throws IOException 如果数据类型转换失败
     */
    private <T> T handleResponse(RpcResponse rpcResponse, Class<T> type) throws IOException {
        // 对响应数据进行特殊处理，确保返回正确的对象类型
        byte[] dataBytes = OBJECT_MAPPER.writeValueAsBytes(rpcResponse.getData());
        rpcResponse.setData(OBJECT_MAPPER.readValue(dataBytes, rpcResponse.getDataType()));
        return type.cast(rpcResponse);
    }
}
